#region Original Source Code License
/*
This code is licensed under BSD. Basically, this means you can do whatever you want with it,
you just can not blame me when something goes wrong or say I endorse whatever it is you decide 
to do. I am very curious to see how and where it is used. Feel free to drop me a line at 
http://scottwater.com/blog/contact.aspx

Now, the legal mumbo jumbo:

Copyright (c) 2003-2006, Scott Watermasysk
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions 
and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or other materials provided
with the distribution. 

Neither the name of Scott Watermasysk, Community Server, Telligent nor the names of its contributors may
be used to endorse or promote products derived from this software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion

#region Addendum
/* 
 * This module was last updated by Robert McLaws on 7 March 2007.
 * It fixes numerous implementation bugs in Scott's original module, as well as adds support for
 * differentiating between image links and text links. It has also been reorganized to fix 
 * readability issues, added error handling, and has been extensively commented where necessary.
*/

#endregion

#region Import Declarations

using System;
using System.Text;
using System.Xml;
using CommunityServer.Blogs.Components;
using CommunityServer.Components;
using System.Web;
using System.Collections;

#endregion

namespace CommunityServerStuff.Modules
{
    /// <summary>
    /// CSModule which renders helpful links at the end of the post in both Web and Rss views.
    /// </summary>
    /// <remarks>
    /// Inspired by Jeremy Zawodny's blog at: http://jeremy.zawodny.com/blog/
    /// Image modifications inspired by WordPress's K2 skin and Neowin.net's redesign.
    /// </remarks>
    public class SharingModule : ICSModule
    {

        #region Private Members

        private bool _appendToFeed = true;
        private bool _appendToWeb = true;
        private DateTime _dateFilter = DateTime.MinValue;
        private string _headerText = "Share this post: ";
        private string _separator = " | ";
        private static readonly string _defaultShareItHtml = "{0}\n<div class = \"shareblock\"><strong>{1}</strong> <a title=\"Email {3}\" href = \"mailto:?body=Thought you might like this: {3}&subject={2}\">Email it!</a> | <a href = \"http://del.icio.us/post?url={3}&title={2}\" title=\"Submit {3} to del.icio.us\" >bookmark it!</a> | <a href = \"http://www.digg.com/submit?url={3}&phase=2\" title=\"Submit {3} to digg.com\">digg it!</a> | <a href = \"http://reddit.com/submit?url={3}&title={2}\" title=\"Submit {3} to reddit.com\">reddit!</a></div>";
        private string _customShareItHtml = null;

        #endregion

        #region Methods

        #region Constructor

        public SharingModule()
        {
        }

        #endregion

        #region Init

        /// <summary>
        /// 
        /// </summary>
        /// <param name="csa"></param>
        /// <param name="node"></param>
        public void Init(CSApplication csa, XmlNode node)
        {
            try
            {
                csa.PreRenderPost += new CSPostEventHandler(csa_PreRenderPost);

                //Load up the variables for the module.
                //This attribute determines whether the HTML should be appended to the post in syndication.
                XmlAttribute synd = node.Attributes["appendToFeed"];
                if (synd != null && synd.Value.ToLower() == "false")
                {
                    _appendToFeed = false;
                }

                //This attribute determines whether the HTML should be appended to the post in the browser.
                XmlAttribute web = node.Attributes["appendToWeb"];
                if (web != null && web.Value.ToLower() == "false")
                {
                    _appendToWeb = false;
                }

                XmlAttribute df = node.Attributes["date"];
                if (df != null)
                {
                    _dateFilter = DateTime.Parse(df.Value);
                }

                //This attribute specifies the lable that will be displayed before the links.
                XmlAttribute header = node.Attributes["headerText"];
                if (header != null)
                {
                    _headerText = header.Value;
                }

                //This attribute specifies the string that will be used to separate the links.
                XmlAttribute sep = node.Attributes["separator"];
                if (sep != null)
                {
                    _separator = sep.Value;
                }

                HttpContext context = HttpContext.Current;

                //The StringBuilder will create the HTML string the module will use to append to the post.
                //This processing will leave some format strings in the HTML so that information like the
                //post title and url can be displayed at render-time.
                StringBuilder sb = new StringBuilder("{0}\n<div class = \"shareblock\"><strong>{1}</strong>");
                bool hasNodes = false;
                foreach (XmlNode linkNode in node.ChildNodes)
                {
                    if (linkNode.NodeType != XmlNodeType.Comment && linkNode.Name == "link")
                    {
                        if (hasNodes)
                            sb.Append(_separator);

                        string linkBody = null;
                        string linkUrl = null;
                        string linkTooltip = null;

                        //Check the type of link & process string accordingly.
                        XmlAttribute currentAttribute = linkNode.Attributes["type"];
                        context.Trace.Warn("Type Attribute: " + currentAttribute.Value);

                        if (currentAttribute.Value.ToLower() == "text")
                        {
                            context.Trace.Warn("Inside text Loop");
                            currentAttribute = linkNode.Attributes["text"];
                            if (currentAttribute == null)
                                continue;
                            //This allows the user to put the post title in the link text.
                            linkBody = currentAttribute.Value.Replace("[postTitle]", "{2}").Replace("[postTitleEncoded]", "{3}");
                        }
                        if (currentAttribute.Value == "image")
                        {
                            context.Trace.Warn("Inside image Loop");
                            currentAttribute = linkNode.Attributes["imageUrl"];
                            if (currentAttribute == null)
                                continue;
                            linkBody = string.Format("<img src=\"{0}\" border=\"0\">", currentAttribute.Value);
                        }
                        context.Trace.Warn("LinkBody Value: " + linkBody);

                        currentAttribute = linkNode.Attributes["linkUrl"];
                        if (currentAttribute == null)
                            continue;
                        //This allows the user to put the post title and post url in the hyperlink target
                        linkUrl = currentAttribute.Value.Replace("[postTitle]", "{2}").Replace("[postTitleEncoded]", "{3}").Replace("[postUrl]", "{4}").Replace("[^]", "&amp;");

                        currentAttribute = linkNode.Attributes["tooltip"];
                        if (currentAttribute == null)
                        {
                            linkTooltip = "Post {4}";
                        }
                        else
                        {
                            //This also allows the user to put the post title and post url in the Tooltip.
                            linkTooltip = currentAttribute.Value.Replace("[postTitle]", "{2}").Replace("[postUrl]", "{4}");
                        }

                        sb.AppendFormat("<a href=\"{0}\" target=\"_blank\" title=\"{1}\">{2}</a>", linkUrl, linkTooltip, linkBody);
                        hasNodes = true;
                    }
                }

                if (hasNodes)
                {
                    sb.Append("</div>");
                    _customShareItHtml = sb.ToString();
                    context.Trace.Warn("Completed String: " + _customShareItHtml);
                }
            }
            catch (Exception e)
            {
                CSException csEx = new CSException(CSExceptionType.UnknownError, "The module RobertMcLaws.CommunityServerStuff.Modules.SharingModule failed while attempting to process the configuration." + Environment.NewLine + e.Message, (e.InnerException != null ? e.InnerException : e));
                csEx.Log();
            }
        }

        #endregion

        #region PreRenderPost

        /// <summary>
        /// 
        /// </summary>
        /// <param name="content"></param>
        /// <param name="e"></param>
        private void csa_PreRenderPost(IContent content, CSPostEventArgs e)
        {
            try
            {
                if (e.Target == PostTarget.Web)
                {
                    if (!_appendToWeb)
                        return;
                }
                else if (e.Target == PostTarget.Syndication)
                {
                    if (!_appendToFeed)
                        return;
                }

                foreach (TextPart tp in e.TextParts)
                {
                    if (string.Compare(tp.Name, "NoSharing", true) == 0 && tp.Count > 1)
                    {
                        content.FormattedBody = tp.Replace(content.FormattedBody, "");
                        return;
                    }
                }

                if (e.ApplicationType == ApplicationType.Weblog)
                {
                    WeblogPost wp = content as WeblogPost;
                    if (wp != null)
                    {

                        bool includePost = (e.Target == PostTarget.Web || wp.PostDate >= _dateFilter);
                        if (wp.PostLevel == 1 && includePost)
                        {
                            string postLink = Globals.FullPath(BlogUrls.Instance().Post(wp));
                            string postTitleEncoded = Globals.UrlEncode(wp.Subject);
                            wp.FormattedBody = string.Format((_customShareItHtml == null) ? _defaultShareItHtml : _customShareItHtml, wp.FormattedBody, _headerText, wp.Subject, postTitleEncoded, postLink);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                CSException csEx = new CSException(CSExceptionType.UnknownError, "The module RobertMcLaws.CommunityServerStuff.Modules.SharingModule failed while attempting to render the post." + Environment.NewLine + ex.Message, (ex.InnerException != null ? ex.InnerException : ex));
                csEx.Log();
            }
        }

        #endregion

        #endregion

    }
}